package desgin.pattern.other.filter;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by kai on 2015/6/28 0028.
 */
public class TestNio2 {
    private static final String LocalCharsetName = "gb2312";
    private SelectClass selectClass;

    public static void main(String[] args) throws IOException {
        System.out.println("hello");
        //start queue
        TestNio2 t2 = new TestNio2();
        t2.startQueue();

        //
        t2.listenScoket();

    }

    public void insertQueue(SocketChannel socketChannel) throws IOException {
        if (selectClass == null) {
            startQueue();
        }
        selectClass.socketQueue.offer(socketChannel);
        selectClass.selector.wakeup();
    }

    public void startQueue() throws IOException {
        selectClass = new SelectClass();
        selectClass.start();
    }

    private final class SelectClass extends Thread {
        private final Selector selector;
        private final BlockingQueue<SocketChannel> socketQueue;

        public SelectClass() throws IOException {
            this.selector = Selector.open();
            this.socketQueue = new LinkedBlockingQueue<>();
        }

        @Override
        public void run() {
            while (true) {
                try {
                    selector.select(1000);
                    SocketChannel sock = socketQueue.poll();
                    if (sock != null) {
                        //register
                        System.out.println("receive sock...");
                        sock.register(selector, SelectionKey.OP_READ);
                        System.out.println(this.selector.selectedKeys().size());
                        Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
                        while (iterator.hasNext()) {
                            SelectionKey key = iterator.next();
                            iterator.remove();
                            ByteBuffer buff = (ByteBuffer) key.attachment();
                            buff.clear();
                            long allBytes = sock.read(buff);
                            if (allBytes == -1) {
                                sock.close();
                            } else {
                                System.out.println("get bytes:" + allBytes);
                                buff.flip();
                                String recvS = Charset.forName(LocalCharsetName).newDecoder().decode(buff).toString();
                                System.out.println("get the cmd string:" + recvS);
                                String sendString = "you send me:" + recvS;
                                buff = ByteBuffer.wrap(sendString.getBytes(LocalCharsetName));
                                sock.write(buff);
                                key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private void listenScoket() throws IOException {
        Selector selector = Selector.open();
        selector.select(500L);

        ServerSocketChannel channel = ServerSocketChannel.open();
        channel.socket().bind(new InetSocketAddress(2222));
        channel.configureBlocking(false);

        channel.register(selector, SelectionKey.OP_ACCEPT);
        for (; ; ) {
            selector.select(2000);
            Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator();
            while (selectionKeys.hasNext()) {
                SelectionKey key = selectionKeys.next();
                selectionKeys.remove();
                if (key.isAcceptable()) {
                    System.out.println("acc");
                    ServerSocketChannel cc = (ServerSocketChannel) key.channel();
                    SocketChannel accept = cc.accept();
                    accept.configureBlocking(false);
                    accept.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                } else if (key.isReadable()) {
                    System.out.println("read..");
                    SocketChannel sock = (SocketChannel) key.channel();
                    insertQueue(sock);
                    System.out.println("already insert to queue;");


                }
            }
        }
    }
}
